package org.tigris.atlas.xml.schema.mda.element;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.tigris.atlas.mda.metadata.MetadataRepository;
import org.tigris.atlas.mda.metadata.element.Entity;
import org.tigris.atlas.mda.metadata.element.Enumeration;
import org.tigris.atlas.mda.metadata.element.Field;

/**
 * Contains schema-related utility methods
 */
public class SchemaElementUtils {

	private static Log log = LogFactory.getLog(SchemaElementUtils.class);

	public static final String SCHEMA_TYPE_STRING = "string";
	public static final String SCHEMA_TYPE_BOOLEAN = "boolean";
	public static final String SCHEMA_TYPE_DATE = "date";
	public static final String SCHEMA_TYPE_DATE_TIME = "dateTime";
	public static final String SCHEMA_TYPE_DECIMAL = "decimal";
	public static final String SCHEMA_TYPE_INT = "int";
	public static final String SCHEMA_TYPE_LONG = "long";
	public static final String SCHEMA_TYPE_DOUBLE = "double";
	public static final String SCHEMA_TYPE_FLOAT = "float";
	public static final String SCHEMA_TYPE_SHORT = "short";

	/**
	 * This method will return the schema type for the given metadata type.  The schema types
	 * are based on the pattern's used in Apache's XMLBeans API.
	 * @param metadataType The type used in metadata
	 * @return The schema-type that corresponds to the metadata type.  If no match is found,
	 * a schema string will be returned
	 */
	static String getSchemaType(String type) {
		String schemaType = null;

		if (Field.TYPE_STRING.equals(type)) {
			schemaType = SCHEMA_TYPE_STRING;
		} else if (Field.TYPE_BOOLEAN.equals(type)) {
			schemaType = SCHEMA_TYPE_BOOLEAN;
		} else if (Field.TYPE_DATE.equals(type)) {
			schemaType = SCHEMA_TYPE_DATE;
		} else if (Field.TYPE_TIMESTAMP.equals(type)) {
			schemaType = SCHEMA_TYPE_DATE_TIME;
		} else if (Field.TYPE_BIG_DECIMAL.equals(type)) {
			schemaType = SCHEMA_TYPE_DECIMAL;
		} else if (Field.TYPE_INTEGER.equals(type)) {
			schemaType = SCHEMA_TYPE_INT;
		} else if (Field.TYPE_LONG.equals(type)) {
			schemaType = SCHEMA_TYPE_LONG;
		} else if (Field.TYPE_CHARACTER.equals(type)) {
			schemaType = SCHEMA_TYPE_STRING;
		} else if (Field.TYPE_DOUBLE.equals(type)) {
			schemaType = SCHEMA_TYPE_DOUBLE;
		} else if (Field.TYPE_FLOAT.equals(type)) {
			schemaType = SCHEMA_TYPE_FLOAT;
		} else if (Field.TYPE_SHORT.equals(type)) {
			schemaType = SCHEMA_TYPE_SHORT;
		} else {
			schemaType = deriveComplexType(type);
			if (schemaType == null) {
				log.error("Metadata type '" + type + "' has no corresponding schema mapping - defaulting to '" +
					SCHEMA_TYPE_STRING + "'");
				schemaType = SCHEMA_TYPE_STRING;
			}
		}

		return schemaType;
	}

	/**
	 * Checks to see if the passed metadata type is a valid entity or enumeration type.  If not,
	 * null is returned
	 * @param metadataType The type to lookup
	 * @return The valid complex type schema name or null
	 */
	private static String deriveComplexType(String metadataType) {
		String schemaType = null;

		MetadataRepository repo = MetadataRepository.getInstance();
		Entity entity = (Entity)repo.getAllEntities().get(metadataType);
		if (entity != null) {
			SchemaEntity schemaEntity = new SchemaEntity(entity);
			schemaType = schemaEntity.getSchemaType();
		} else {
			Enumeration enumeration = (Enumeration)repo.getAllEnumerations().get(metadataType);
			if (enumeration != null) {
				SchemaEnumeration schemaEnumeration = new SchemaEnumeration(enumeration);
				schemaType = schemaEnumeration.getSchemaType();
			}
		}

		return schemaType;
	}

	/**
	 * Returns the schema type for this complex object.
	 * @param complexTypeMetadataName The name of the complex object to resolve
	 */
	static String getComplexTypeSchemaType(String complexTypeMetadataName) {
		StringBuffer sb = new StringBuffer(150);
		sb.append(complexTypeMetadataName);
		return sb.toString();
	}

	/**
	 * Return namespace name of this instance (ie, the 'xs' part of 'xmlns:xs')
	 */
	static String getNamespaceName(String project, String type) {
		StringBuffer sb = new StringBuffer(150);
		if (!StringUtils.isBlank(project)) {
			sb.append(project).append("-");
		}
		sb.append(type.toLowerCase());
		return sb.toString();
	}

	/**
	 * Returns relative location of the namespace
	 */
	static String getNamespaceLocation(String project, String name) {
		return name;
	}

	/**
	 * Turns a java-style base package, such as "com.foo.bar" into
	 * a schema-style base namespace, such as "bar.foo.com"
	 * @param basePackage The package to translate
	 * @return The resulting namespace
	 */
	public static String translateBasePackageToBaseSchemaLocation(String basePackage) {
		return StringUtils.reverseDelimited(basePackage, '.');
	}
}
